/***********************************************************************************
Copy right:	    Coffee Tech.
Author:         jiaoyue
Date:           2021-11-21
Description:    设备上报服务
***********************************************************************************/

#include "dr_service.h"
#include "report_handler.h"
#include "random.h"

struct global_data g_data = {0};
static struct shm_param para;
static struct node_cache _node_cache;
static struct report_type _report_type;

struct unix_param unix_dc; //给设备采集进程用
struct unix_param unix_ec; //给边缘采集进程用

//#define ANALOG  //是否利用模拟数据产生

int init_unix_client()
{
    int ret;
    ret = unix_init_client(&unix_dc, MODULE, DC_NAME);
    if(ret < 0)
    {
        LOGE("dc unix_init_client err");
        return -1;
    }

    ret = unix_init_client(&unix_ec, MODULE, EC_NAME);
    if(ret < 0)
    {
        LOGE("ec unix_init_client err");
        return -1;
    }

    return 0;
}

/**
 * @brief 初始化服务
 * @return 0 -1
 */
int init_dr_service()
{
    //生成共享内存点缓存
    int ret = -1;

    ret = shm_init(&para, EDGE_SHM_NAME, MAX_NODE_SIZE);
    if(ret < 0)
    {
        return -1;
    }

    void *node_p = shm_getaddr(&para);
    if(node_p == NULL)
    {
        return -1;
    }

    memset(node_p, 0, MAX_NODE_SIZE);

    //前4个字节存储实际的点数
    _node_cache.total = (int *)node_p;
    //后面空间存储数据点
    _node_cache.node_p = (struct std_node *)(node_p + sizeof(int));

    g_data.node_cache_p = &_node_cache;  //赋值全局指针，以便其它文件能使用

    //解析点表
    struct list_head nv_list;

    nv_get_list_from_file(&nv_list, NODE_CONFIG_PAHT);
    struct nv_obj *pobj;

    //解析上报方式
    pobj = nv_get_list_obj(&nv_list, "report.type");
    if(NULL == pobj)
    {
        LOG_STD(APP_ERR, "get report.type err");
        return -1;
    }
    _report_type.type = pobj->valueint;

    pobj = nv_get_list_obj(&nv_list, "report.period");
    if(NULL == pobj)
    {
        LOG_STD(APP_ERR, "get report.period err");
        return -1;
    }
    _report_type.period = pobj->valueint;

    g_data.report_type_p = &_report_type;

    //解析节点数组
    //解析m0的数据点
    int arr_size = -1;
    pobj = nv_get_list_obj(&nv_list, "m0.data.arr_size");
    if(NULL == pobj)
    {
        LOG_STD(APP_ERR, "get err");
    }
    arr_size = pobj->valueint;
    LOG_STD(APP_DEBUG, "m0 arr size = %d", arr_size);

    int node_count = 0;
    for (int i=0; i<arr_size; i++)
    {
        char key_str[256] = {0};
        char type_str[256] = {0};

        snprintf(key_str, 255, "m0.data[%d].key", i);
        snprintf(type_str, 255, "m0.data[%d].type", i);

        pobj = nv_get_list_obj(&nv_list, key_str);
        _node_cache.node_p[node_count].key = pobj->valueint;
        pobj = nv_get_list_obj(&nv_list, type_str);
        _node_cache.node_p[node_count].type = pobj->valueint;
        _node_cache.node_p[node_count].dev_type = DEV_TYPE_M0;
        node_count++;
    }

    //解析modbus数据点
    pobj = nv_get_list_obj(&nv_list, "modbus.data.arr_size");
    if(NULL == pobj)
    {
        LOG_STD(APP_ERR, "get err");
    }
    arr_size = pobj->valueint;
    LOG_STD(APP_DEBUG, "modbus arr size = %d", arr_size);

    for (int i=0; i<arr_size; i++)
    {
        char key_str[256] = {0};
        char type_str[256] = {0};

        snprintf(key_str, 255, "modbus.data[%d].key", i);
        snprintf(type_str, 255, "modbus.data[%d].type", i);

        pobj = nv_get_list_obj(&nv_list, key_str);
        _node_cache.node_p[node_count].key = pobj->valueint;
        pobj = nv_get_list_obj(&nv_list, type_str);
        _node_cache.node_p[node_count].type = pobj->valueint;
        _node_cache.node_p[node_count].dev_type = DEV_TYPE_MB;
        node_count++;
    }

    //记录下实际点数值
    *_node_cache.total = node_count;

    //nv_get_list和nv_list_free成对存在
    nv_list_free(&nv_list);

    //调试下看看
    
    LOG_STD(APP_DEBUG, "node_count = %d", *_node_cache.total);
    for (int i = 0; i < *_node_cache.total; i++)
    {
        LOG_STD(APP_DEBUG, "node[%d].key=%d", i, _node_cache.node_p[i].key);
    }
    
    //初始化unix_sock的客户端
    ret = unix_init_client(&g_data.dc_para, MODULE, DC_NAME);
    if(ret < 0)
    {
        LOG_STD(APP_ERR, "unix_init_client err");
        return -1;
    }

    ret = unix_init_client(&g_data.ec_para, MODULE, EC_NAME);
    if(ret < 0)
    {
        LOG_STD(APP_ERR, "unix_init_client err");
        return -1;
    }

//测试使用，产生模拟数据
#ifdef ANALOG
    void *data_analog_thread(void *arg);
    pthread_t tid;
    pthread_create(&tid, NULL, data_analog_thread, NULL);
#endif

    return 0;
}

#ifdef ANALOG
void *data_analog_thread(void *arg)
{
    LOG_STD(APP_NOTICE, "data_analog_thread");
    int node_count = *_node_cache.total;
    struct std_node *node_p = _node_cache.node_p; 
    set_really_random();

    while (1)
    {
        for (int i = 0; i < node_count; i++)
        {
            if(node_p[i].type == NODE_TYPE_BOOL)
            {
                node_p[i].new_val.b_val = random_int(0, 2);
            }
            else if(node_p[i].type == NODE_TYPE_INT)
            {
                node_p[i].new_val.i_val = random_int(10, 20);
            }
            else if(node_p[i].type == NODE_TYPE_FLOAT)
            {
                node_p[i].new_val.f_val = random_float(10, 20);
            }
        }
        sleep(1);  //1s产生一次数据
    }
}
#endif

/**
 * @brief 数据上报线程
 * @param arg
 * @return
 */
void *data_report_thread(void *arg)
{
    //根据不同的上报类型执行不同的上报策略
    switch (_report_type.type)
    {
    case REPORT_TYPE_NONE:  //不上报
        report_none_handler();
        break;
    case REPORT_TYPE_CHANGE:  //变化上报
        report_change_handler();
        break;
    case REPORT_TYPE_PERIOD:  //定时上报
        report_period_handler();
        break;
    default:
            
        break;
    }
    sleep(100);

    return NULL;
}


/**
 * @brief 接收来自上层进程的指令，解析并处理
 * @param arg
 * @return
 */
void *msg_handle_thread(void *arg)
{
    while (1)
    {
        sleep(100);
    }
    
    return NULL;
}

